#define _FILE_OFFSET_BITS  64
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include "swaping.h"
FILE* SWAP_FILE;

int swap_init(const char* swap_path, off_t swap)
{
	// K: maybe add O_TRUNC flag? 
	int SWAPfd = open(swap_path, O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
	// K: Maybe rlimit is more suitable here.
	if(SWAPfd==-1){
		errno=(errno==EACCES)?EACCES:EFAULT;
		goto fail;
	}else{
		if (posix_fallocate(SWAPfd, 0, swap) != 0) {
			errno = EFBIG;
			goto fail;
		} else {
			SWAP_FILE = fdopen(SWAPfd, "w+");
		}
		if (SWAP_FILE == NULL) {
			goto fail;
		}
	}
	
	return 1;
fail:
	return 0;
}
/*puts data in swap. Sets "something bad with swap file" error*/

int mem2swap(void* src_ptr, off_t dest_offset, size_t size)
{
	if (fseeko(SWAP_FILE, dest_offset, SEEK_SET) == -1) {
		goto fail;
	}
	if (fwrite(src_ptr, 1, size, SWAP_FILE) != size) {
		goto fail;
	}
#ifdef DEBUG
	fflush(SWAP_FILE);
#endif

	return 1;
fail:
	errno = EBADF;
	return 0;
}

/*get data from swap. Sets "something bad with swap file" error*/

int swap2mem(off_t src_offset, void* dest_ptr, size_t size)
{
	if (fseeko(SWAP_FILE, src_offset, SEEK_SET)) {
		goto fail;
	}
	if (fread(dest_ptr, 1, size, SWAP_FILE) != size) {
		goto fail;
	}

	return 1;
fail:
	errno = EBADF;
	return 0;
}

int swap2swap(off_t src_offset, off_t dest_offset, size_t _size){
	size_t tmp, i, size = _size / sizeof(size_t);
	int mod;
	for (i = 0; i < size; i++) {
		if (fseeko(SWAP_FILE, src_offset + i * sizeof(size_t), SEEK_SET)) {
			goto fail;
		}
		if (fread(&tmp, sizeof(size_t), 1, SWAP_FILE) != 1) {
			goto fail;
		}
		if (fseeko(SWAP_FILE, dest_offset + i * sizeof(size_t), SEEK_SET)) {
			goto fail;
		}
		if (fwrite(&tmp, sizeof(size_t), 1, SWAP_FILE) != 1) {
			goto fail;
		}
	}
	mod = _size % sizeof(size_t);
	if (mod) {
		if (fseeko(SWAP_FILE, src_offset + size * sizeof(size_t), SEEK_SET)) {
			goto fail;
		}
		if (fread(&tmp, mod, 1, SWAP_FILE) != 1) {
			goto fail;
		}
		if (fseeko(SWAP_FILE, dest_offset + i * sizeof(size_t), SEEK_SET)) {
			goto fail;
		}
		if (fwrite(&tmp, mod, 1, SWAP_FILE) != 1) {
			goto fail;
		}
	}
	
#ifdef DEBUG
	fflush(SWAP_FILE);
#endif
	return 1;
fail:
	errno = EBADF;
	return 0;
}

void swap_deinit()
{
	fclose(SWAP_FILE);
}